package server

import (
	"cgs-server/server/model"
	"context"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"net/http"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"

	"cgs-server/server/system"
)

// GetCurrentUser get the current login user. It returns nil if there is something wrong.
func GetCurrentUser(r *http.Request) (*system.User, error) {
	var cookie *http.Cookie = nil
	for _, item := range r.Cookies() {
		if item.Name == "token" {
			cookie = item
			break
		}
	}

	// get current user
	var user *system.User = nil

	TokenValue := ""
	if cookie != nil {
		TokenValue = cookie.Value
	} else {
		if len(r.Header) > 0 {
			for k, v := range r.Header {
				if k == "Auth-Token" {
					TokenValue = v[0]
					break
				}
			}
		}
	}

	//if cookie != nil {
	if TokenValue != "" {
		token, err := jwt.Parse(TokenValue, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}
			return []byte(Config.Authority.SecretKey), nil
		})
		if err != nil {
			return nil, err
		}
		if claims, ok := token.Claims.(jwt.MapClaims); ok && token != nil && token.Valid {
			user, _ = GetUser(claims["userID"].(string))
		} else {
			Logger.Error(err.Error())
		}
		//check token
		db, err := Mongo()
		if err != nil {
			fmt.Println(err)
			user = nil
		}
		tokenFilter := bson.M{
			"TokenValue": TokenValue,
			"Enabled":    1,
		}
		docs := bson.M{}
		find, err := db.FindOne(CgsTokenCollectionName, tokenFilter, &docs)
		if !find || err != nil {
			return nil, err
		}

		ctx := context.WithValue(r.Context(), "token", TokenValue)
		nr := r.WithContext(ctx)
		*r = *nr

	} else {
		//Get User by APPKey
		userID := r.Context().Value("userID")
		if userID != nil {
			user, _ = GetUser(userID.(string))
		}
	}
	//if tokenvalue != "" check token enabled
	//}

	// user has LOGIN auth when login
	if user != nil && user.OperatingAuthorities != nil {
		user.OperatingAuthorities = append(user.OperatingAuthorities, string(Login))
	}

	return user, nil
}

// GetUser get a user from userID.
func GetUser(userID string) (*system.User, error) {
	// parse ObjectID
	userObjectID, err := primitive.ObjectIDFromHex(userID)
	if err != nil {
		return nil, err
	}

	// create mongo client
	mongo, err := Mongo()
	if err != nil {
		return nil, err
	}

	// get user from mongo
	filter := bson.M{
		"ID": userObjectID,
	}
	user := system.User{}
	user.OperatingAuthorities = []string{}
	find, err := mongo.FindOne(UserCollectionName, filter, &user)
	if err != nil {
		return nil, err
	}
	if !find { // user is not found
		return nil, nil
	}

	// 查询租户是否存在，否则该租户的用户都不能使用
	/*tenantRes := bson.M{}
	filter = bson.M{
		"tenantId": user.TenantId,
		"isDeleted": 0,
	}
	find, err = mongo.FindOne(Tenant, filter, &tenantRes)
	if err != nil {
		return nil, err
	}
	if !find {
		return nil, nil
	}*/

	// user's RoleID is empty
	if user.RoleID == "" {
		return &user, nil
	}

	// get roles and authorities
	roleObjectID, err := primitive.ObjectIDFromHex(user.RoleID)
	if err != nil {
		return nil, err
	}

	filter = bson.M{
		"ID": roleObjectID,
	}

	role := model.Role{}
	find, err = mongo.FindOne(RoleCollectionName, filter, &role)
	if err != nil {
		return nil, err
	}

	// role is not found
	if !find {
		return &user, nil
	}

	// find role
	user.RoleID = role.Id.Hex()
	user.RoleName = role.RoleAlias // 这里英文的名称

	if role.RoleAlias == "Administrator" || role.RoleAlias == "AppAdministrator" {
		// Administrator has all the authorities except Initialize
		for _, v := range GetAllAuthorities() {
			if role.RoleAlias == "AppAdministrator" && v.ID == string(ManageBackend) {
				continue
			}
			user.OperatingAuthorities = append(user.OperatingAuthorities, v.ID)
		}
		if user.TenantId == "000000" {
			user.OperatingAuthorities = append(user.OperatingAuthorities, string(SuperAdministrator))
		}
	} else {
		// other roles get authorities from operating authority collection
		filter := bson.M{
			"roleId": role.Id.Hex(),
		}

		cursor, err := mongo.Find(RoleAuthorityCollectionName, filter)
		if err != nil {
			return nil, err
		}

		for cursor.Next(context.TODO()) {
			authority := model.RoleAuthority{}
			if err := cursor.Decode(&authority); err != nil {
				continue
			}

			user.OperatingAuthorities = append(user.OperatingAuthorities, authority.AuthorityName)
		}
	}

	// 获取应用角色及权限
	// 1. 在用户角色管理表查询用户的所有(应用)角色
	filter = bson.M{
		"userId": userID,
	}
	userRoles := []*model.UserRole{}
	if err := mongo.FindMany(UserRole, filter, &userRoles); err != nil {
		return nil, err
	}
	if len(userRoles) == 0 {
		return &user, nil
	}
	// 根据id查询所有的角色，
	ids := []primitive.ObjectID{}
	for i := range userRoles {
		id, err := primitive.ObjectIDFromHex(userRoles[i].RoleId)
		if err != nil {
			return nil, err
		}
		ids = append(ids, id)
	}
	filter = bson.M{
		"ID": bson.M{
			"$in": ids,
		},
	}
	roles := []*model.Role{}
	if err := mongo.FindMany(RoleCollectionName, filter, &roles); err != nil {
		return nil, err
	}
	if len(roles) == 0 {
		return &user, nil
	}
	if user.AppAuths == nil {
		user.AppAuths = make(map[string][]string, len(roles))
	}
	if user.VisualAppMap == nil {
		user.VisualAppMap = make(map[string][]primitive.ObjectID)
	}
	for i := range roles {
		visualId := roles[i].VisualId
		user.AppAuths[visualId] = []string{}
		if user.VisualAppMap[visualId] == nil {
			user.VisualAppMap[visualId] = make([]primitive.ObjectID, 0)
		}
		user.VisualAppMap[visualId] = append(user.VisualAppMap[visualId], roles[i].Id)
	}

	return &user, nil
}

type Token struct {
	UserID     string
	TokenValue string
	Enabled    int //0 false 1 true
}
